﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Threading;
using ch.froorider.NGoogleCalendar.googleService;
using ch.froorider.NGoogleCalendar.tools;

namespace ch.froorider.NGoogleCalendar.console
{
	public class Program
	{
		private static string accountName = ConfigurationManager.AppSettings["AccountName"];
		private static string password = ConfigurationManager.AppSettings["DefaultPassword"];
		private static bool isAccountValid = false;
		private static bool done = false;
		private static Calendar calendar;
		private static BackgroundWorker worker = new BackgroundWorker();
		private static String[] userCredentials = null;

		static void Main(string[] args)
		{
			Console.WriteLine("Welcome to NGoogleCalendar");
			Console.Title = "NGoogleCalendar";

			AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);

			worker.DoWork += new DoWorkEventHandler(CreateCalendar);

			do
			{
				Console.WriteLine("Main menu:");
				Console.WriteLine("\t1 -- Enter your account information.");
				Console.WriteLine("\t2 -- List of available calendars.");
				Console.WriteLine("\t3 -- List of entries.");
				Console.Write("Enter your selection (0 to exit): ");
				string strSelection = Console.ReadLine();
				int iSel;
				try
				{
					iSel = int.Parse(strSelection);
				}
				catch (FormatException)
				{
					Console.WriteLine("\r\nWhat?\r\n");
					continue;
				}
				Console.WriteLine("You selected  " + iSel);
				switch (iSel)
				{
					case 0:
						done = true;
						break;
					case 1:
						VerifyUserCredentials();
						break;
					case 2:
						ShowCalendarList();
						break;
					case 3:
						ShowEntries();
						break;
					default:
						Console.WriteLine("You have selected an invalid number: {0}\r\n", iSel);
						continue;
				}
				Console.WriteLine();
			}
			while (!done);
			Console.WriteLine("\nGoodbye!");
		}

		#region methods

		/// <summary>
		/// Tries to validate if a username / password combination is valid, and the needed
		/// can be accessed.
		/// </summary>
		private static void VerifyUserCredentials()
		{
			Console.Clear();

			while (!isAccountValid)
			{
				while (!parseArguments(userCredentials))
				{
					Console.WriteLine("Please enter your username and password.");
					String inputArguments = Console.ReadLine();
					userCredentials = inputArguments.Split(' ');
					Console.Clear();
				}

				worker.RunWorkerAsync();
				
				while (worker.IsBusy)
				{
					Thread.Sleep(1000);
					Console.Write("*");
				}

				Console.WriteLine();
			}
		}

		/// <summary>
		/// Prints all available calendar names on the output stream.
		/// </summary>
		private static void ShowCalendarList()
		{
			Console.Clear();
			if (isAccountValid)
			{
				Console.WriteLine("Getting calendar list.");
				List<String> calendarNames = calendar.GetCalendarList();
				foreach (String calendarname in calendarNames)
				{
					Console.WriteLine("Calendar: {0}", calendarname);
				}
			}
			else
			{
				Console.WriteLine("Please enter first your account information.");
			}
		}

		/// <summary>
		/// Prints the events / entries of the calendar on the output stream.
		/// </summary>
		private static void ShowEntries()
		{
			Console.Clear();
			if (isAccountValid)
			{
				Console.WriteLine("Getting event list.");
				List<String> eventList = calendar.GetTaskList();
				foreach (String eventName in eventList)
				{
					Console.WriteLine("Event: {0}", eventName);
				}
			}
			else
			{
				Console.WriteLine("Please enter first your account information.");
			}
		}

		#endregion

		#region additional functionality

		/// <summary>
		/// Is called whenever an object throws an exception which is not caught by anyone.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
		{
			Exception concreteException = (Exception)e.ExceptionObject;
			Console.WriteLine("Unhandled Exception caught: " + concreteException.Message);
			Console.WriteLine("Stack Trace: " + concreteException.StackTrace);
		}

		/// <summary>
		/// Looks if the needed arguments are available.
		/// </summary>
		/// <param name="arguments">An arry of string inputted by the user</param>
		/// <returns>true if there are two non-empty arguments; false if not</returns>
		private static Boolean parseArguments(string[] arguments)
		{
			if (arguments == null)
			{
				return false;
			}
			else
			{
				if (arguments.Length < 2 || String.IsNullOrEmpty(arguments[0]) || String.IsNullOrEmpty(arguments[1]))
				{
					return false;
				}
				else
				{
					return true;
				}
			}
		}
		#endregion

		#region BackgroundWorker

		/// <summary>
		/// Because this operation can take some seconds we put it in a background thread.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private static void CreateCalendar(object sender, DoWorkEventArgs e)
		{
			string accountName = null;
			string password = null;

			try
			{
				accountName = userCredentials[0];
				password = userCredentials[1];
			}
			catch (Exception exp)
			{
				Console.WriteLine("Exception catched: " + exp.StackTrace);
			}

			try
			{
				Console.WriteLine("Opening account: {0}", accountName);
				calendar = new Calendar(accountName, password);
				isAccountValid = true;
			}
			catch (NGoogleCalendarException ngce)
			{
				Console.WriteLine("Something with your account is wrong.");
				Console.WriteLine("Message: " + ngce.Message);
				userCredentials = null;
			}
		}

		#endregion
	}
}
